﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint;
using System.IO;
using System.Xml;
using System.Threading;

namespace Winwise.SPWebConfig.Core
{
    public enum WebModificationsUpgradeType
    {
        Incremential,
        Full
    }
    public static class ExtensionWebApplication
    {
        public static WebConfigFileChanges GetCustomWebConfigModifications(this SPWebApplication webapp)
        {
            WebConfigFileChanges filechanges = (SPFarm.Local.GetObject(WebConfigFileChanges.GenerateName(),
                    webapp.Id, typeof(WebConfigFileChanges))) as WebConfigFileChanges;
            if (filechanges == null)
            {
                filechanges = new WebConfigFileChanges(WebConfigFileChanges.GenerateName(), webapp);
                if (SPContext.Current != null && SPContext.Current.Web != null)
                {
                    SPContext.Current.Web.AllowUnsafeUpdates = true;
                }
                filechanges.Update();
            }
            return filechanges;
        }

        public static void WaitUntilEndOfWebConfigModification(this SPWebApplication webapp)
        {
            bool found = false;
            do
            {
                found = false;
                foreach (SPJobDefinition jobdef in webapp.JobDefinitions)
                {
                    if (jobdef.Name == "winwise-job-webconfig-modification")
                    {
                        found = true;
                    }
                }
                foreach (SPRunningJob job in webapp.RunningJobs)
                {
                    if (job.JobDefinitionTitle == "winwise-job-webconfig-modification")
                    {
                        found = true;
                    }
                }
                Thread.Sleep(1000);


            } while (found);
        }

        public static void ApplyCustomWebConfigModifications(this SPWebApplication webapp, WebModificationsUpgradeType upgradeType)
        {
            WebConfigJobDefinition definition = new WebConfigJobDefinition(webapp)
            {
                Schedule = new SPOneTimeSchedule(DateTime.Now),
                UpgradeType = upgradeType,
                WebModifID = Guid.Empty
            };
            try
            {
                definition.Update();
                return;
            }
            catch (Exception exception)
            {
                if (exception is SPDuplicateObjectException)
                {
                    throw new InvalidOperationException(SPResource.GetString("WebconfigModificationAlreadyRunning", new object[0]), exception);
                }
                throw;
            }
        }

        public static void ApplyCustomWebConfigModifications(this SPWebApplication webapp, Guid webModifID)
        {
            WebConfigJobDefinition definition = new WebConfigJobDefinition(webapp)
            {
                Schedule = new SPOneTimeSchedule(DateTime.Now),
                WebModifID = webModifID
            };
            try
            {
                definition.Update();
                return;
            }
            catch (Exception exception)
            {
                if (exception is SPDuplicateObjectException)
                {
                    throw new InvalidOperationException(SPResource.GetString("WebconfigModificationAlreadyRunning", new object[0]), exception);
                }
                throw;
            }
        }


        public static void ApplyCustomWebConfigModificationsLocalServer(this SPWebApplication webapp, WebModificationsUpgradeType UpgradeType, Guid OnlyWebModifID)
        {
            WebConfigFileChanges globalChanges = (SPFarm.Local.GetObject(WebConfigFileChanges.GenerateName(),
                    webapp.Id, typeof(WebConfigFileChanges))) as WebConfigFileChanges;

            if (OnlyWebModifID != Guid.Empty)
            {
                UpgradeType = WebModificationsUpgradeType.Full;
            }

            if (globalChanges == null)
            {
                globalChanges = new WebConfigFileChanges();
            }

            foreach (var iisZone in webapp.IisSettings)
            {
                SPUrlZone zone = iisZone.Key;
                Guid ServerID = SPServer.Local.Id;

                string oldnameChanges = WebConfigFileChanges.GenerateNameByServerAndZone(ServerID, zone);
                WebConfigFileChanges localChanges =
                     (SPFarm.Local.GetObject(oldnameChanges, webapp.Id, typeof(WebConfigFileChanges))) as WebConfigFileChanges;

                if (localChanges == null)
                {
                    localChanges = new WebConfigFileChanges(oldnameChanges, webapp);
                }

                SPIisSettings iis = iisZone.Value;

                string webconfigpath = Path.Combine(iis.Path.ToString(), "web.config");
                string oldwebconfigpath = Path.Combine(iis.Path.ToString(), "web.config" + DateTime.Now.ToString("dd-mm-ss"));

                if (!File.Exists(webconfigpath))
                {
                    //PB : file is not there
                    localChanges.LogError("web.config file not found at " + webconfigpath);
                    continue;
                }

                XmlDocument olddoc = new XmlDocument();
                XmlDocument newdoc = new XmlDocument();

                try
                {
                    olddoc.Load(webconfigpath);
                    newdoc.Load(webconfigpath);
                }
                catch (Exception e)
                {
                    string message = String.Format("Error loading web.config in XMLDocument:{0}. Error : {1}",
                        webconfigpath, e.ToString());
                    localChanges.LogError(message);
                    continue;
                }

                try
                {
                    List<Guid> ExcludedModifs = null;
                    if (UpgradeType == WebModificationsUpgradeType.Incremential)
                    {
                        ExcludedModifs = new List<Guid>(globalChanges.WebModif.Select(m => m.ID));
                    }
                    localChanges.RemoveModifications(newdoc, zone, webapp, ExcludedModifs, OnlyWebModifID);
                }
                catch (Exception e)
                {
                    localChanges.LogError("Error Removing Web Config modifications:  " + e.ToString());
                }

                List<WebConfigModification> oldModifs = localChanges.WebModif;
                localChanges.WebModif = globalChanges.WebModif;

                try
                {
                    List<Guid> ExcludedModifs = null;
                    if (UpgradeType == WebModificationsUpgradeType.Incremential)
                    {
                        ExcludedModifs = new List<Guid>(oldModifs.Select(m => m.ID));
                    }
                    localChanges.ApplyModifications(newdoc, zone, webapp, ExcludedModifs, OnlyWebModifID);
                }
                catch (Exception e)
                {
                    localChanges.LogError("Error Applying Web Config modifications:  " + e.ToString());
                }

                if (olddoc.OuterXml != newdoc.OuterXml)
                {
                    try
                    {
                        File.Copy(webconfigpath, oldwebconfigpath);
                        newdoc.Save(webconfigpath);
                    }
                    catch (Exception e)
                    {
                        localChanges.LogError("Error Saving file after Web Config modifications:  " + e.ToString());
                        continue;
                    }
                }
              
                localChanges.Update();
            }
        }

        

        internal static void ApplyCustomWebConfigModificationsLocalServer(this SPWebApplication webapp, WebModificationsUpgradeType UpgradeType)
         {
             webapp.ApplyCustomWebConfigModificationsLocalServer(UpgradeType, Guid.Empty);
         }
    }
}
